//import * as dragData from './dragData.js';

function calculateDragLatency(ft, fy, lt, ldir)
{
// 先清理数据
//    console.log("ft1:", ft);
    var i = 0;
    while (i < ft.length){
        if(ft[i] < 0){
            var j = i + 1;
            while (j < ft.length && ft[j] < 0){
                j += 1;
            }
            ft[i] = ft[i-1] + (ft[j] - ft[i-1]) / (j - i + 1);
        }
        i+=1;
    }
//    console.log("ft2:", ft);

	var ly = interp(lt, ft, fy);
    var sideIdx = new Array(lt.length);
    for (var i = 0; i< lt.length; i++) {
		sideIdx[i] = ((i+1) / 2) % 2;
	}

    var averageBestShift = 0;
	for(var side = 0; side < 2; side++) {
		var lts = extract(sideIdx, side, lt);
		var bestShift = findBestShift(lts, ft, fy);
//		console.log("bestShift = " + bestShift.toFixed(2));
		averageBestShift += bestShift / 2;
	}
//	console.log("Drag latency is " + averageBestShift.toFixed(2));
	return averageBestShift;
}

function interp(x, xp, yp) {
		// assuming that x and xp are already sorted.
		// go over x and xp as if we are merging them
		var y = new Array(x.length);
		var i = 0;
		var ip = 0;

		// skip x points that are outside the data
		while (i < x.length && x[i] < xp[0]) i++;

		while (ip < xp.length && i < x.length) {
			// skip until we see an xp >= current x
			while (ip < xp.length&& xp[ip] < x[i]) ip++;
			if (ip >= xp.length) break;
			if (xp[ip] == x[i]) {
				y[i] = yp[ip];
			} else {
				var dy = yp[ip] - yp[ip-1];
				var dx = xp[ip] - xp[ip-1];
				y[i] = yp[ip-1] + dy/dx * (x[i] - xp[ip-1]);
			}
			i++;
		}
//		console.log(y);
		return y;
}

function extract(indicator, value, arr) {
		var newLen = 0;
		indicator.forEach(function(v) { if (v == value) newLen++; });
		var newx = new Array(newLen);

		var j = 0;
		for (var i=0; i<arr.length; i++) {
			if (indicator[i] == value) {
				newx[j] = arr[i];
				j++;
			}
		}
		return newx;
}


function findBestShift(laserT, touchT, touchY) {

    var steps = 1500;
    var shiftSteps = [0.1, 0.01];  // milliseconds
    var stddevs = new Array(steps);

    var bestShift = shiftSteps[0]*steps/2;
    shiftSteps.forEach(function(shiftStep) {
        for (var i = 0; i < steps; i++) {
            stddevs[i] = getShiftError(laserT, touchT, touchY, bestShift + shiftStep * i - shiftStep * steps / 2);
        }
        bestShift = argmin(stddevs, steps) * shiftStep + bestShift - shiftStep * steps / 2;
    });
    return bestShift;
}

function getShiftError(laserT, touchT, touchY, shift) {

    var T = new Array(laserT.length);

    for (var j=0; j<laserT.length; j++) {
        T[j] = laserT[j] + shift;
    }
    var laserY = interp(T, touchT, touchY);
    // TODO: Think about throwing away a percentile of most distanced points for noise reduction
    return stdev(laserY);
}

function argmin(a, length) {
    var imin = 0;
    for (var i=1; i<length; i++){
        if (a[i] < a[imin]){
            imin = i;
        }
    }
    return imin;
}

function stdev(a) {
    var m = mean(a);
    var sumsq = 0;
    a.forEach(function(v) { sumsq += (v-m)*(v-m); });
    return Math.sqrt(sumsq / a.length);
}

function mean(x) {
    var s = 0;
    x.forEach(function(v) { s += v; });
    return s / x.length;
}

export { calculateDragLatency};

//calculateDragLatency(data.finger_time, data.finger_pos, data.laser_time, data.laser_pos);